<template>
	<view class="com-gesture-password position-relative" ref="comGesturePassword" @touchstart="touchstart" @touchmove="touchmove" @touchend="touchend">
		<com-grid :data="data" :column="3" :gap="gap + 'px'">
			<template v-slot="{item, index}">
				<view class="y-flex y-flex-1 y-align-center y-justify-center">
					<view :ref="'btn'+index" class="pwd-btn y-flex y-align-center y-justify-center border-1"
					:style="{'border-color': selected.findIndex(s => s.value == item) > -1 ? selectedColor : color}">
						<view class="pwd-btn-circle" :style="{'background-color': selected.findIndex(s => s.value == item) > -1 ? selectedColor : color}"></view>
					</view>
				</view>
			</template>
		</com-grid>
		<view class="line position-absolute" ref="line" v-for="(s, i) in selected" :key="i"
		:style="{
			'top': s.top + 'px',
			'left': s.left + 'px',
			'background-color': selectedColor,
			'transform': 'rotateZ(' + s.rotate + 'deg)',
			'width': s.width + 'px'
		}"></view>
	</view>
</template>

<script>
	const dom = uni.requireNativePlugin('dom')
	const Binding = uni.requireNativePlugin('bindingx')
	export default {
		props: {
			//未选中颜色
			color: {
				type: String,
				default: '#333'
			},
			//选中高亮色
			selectedColor: {
				type: String,
				default: '#007aff'
			},
			//按钮间距
			gap: {
				type: [Number, String],
				default: 60
			},
			//允许重复
			allowRepeat: {
				type: Boolean,
				default: false
			},
			max: {
				type: Number,
				default: -1
			}
		},
		data () {
			return {
				data: [1,2,3,4,5,6,7,8,9],
				isTouch: false,
				selected: [],
				rect: []
			}
		},
		mounted () {
			this.$nextTick(() => {
				setTimeout(() => {
					this.updateSize()	
				}, 100)
			})
		},
		methods: {
			async updateSize () {
				this.rect = []
				const box = await this.getRect(this.$refs.comGesturePassword)//获取组件尺寸信息
				for ( let i = 0; i < this.data.length; i++ ) {
					const rect = await this.getRect(this.$refs['btn'+i])
					//记录每个按钮的位置信息，以及计算按钮的中心位置，因为获取到的按钮位置是相对于整个屏幕的位置，所以需要将按钮的位置减去组件的位置，这样才能算出按钮相对于组件的位置
					this.rect.push({...rect,
						top: rect.top - box.top,
						left: rect.left - box.left,
						right: rect.right - box.left,
						bottom: rect.bottom - box.top,
						centerTop: rect.height / 2 + rect.top - box.top - 5 / 2,//减去2.5的像素，是因为直线高度为5px
						centerLeft: rect.width / 2 + rect.left - box.left
					})
				}
			},
			touchstart (e) {
				if ( this.isTouch ) return
				const touch = e.touches[0]
				//判断是否从按钮开始触摸
				const index = this.rect.findIndex(r => touch.pageX >= r.left && touch.pageX <= r.right && touch.pageY >= r.top && touch.pageY <= r.bottom )
				if ( index > -1 ) {
					this.isTouch = true
					this.selected.push({
						value: this.data[index],
						top: this.rect[index].centerTop,
						left: this.rect[index].centerLeft,
						rotate: 0,
						width: 0,
						isFinish: false//直线是否画完
					})
				}
			},
			touchmove (e) {
				if ( !this.isTouch ) return
				const touch = e.touches[0]
				if ( this.selected.length > 0 ) {
					const s = this.selected[this.selected.length-1]
					const deltaY = touch.pageY - s.top
					const deltaX = touch.pageX - s.left
					//根据坐标位置计算旋转角度
					s.rotate = Math.atan2(deltaY, deltaX) * (180 / Math.PI)
					//计算直线宽度
					s.width = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
				}
				//判断是否当前坐标点是否有按钮
				const index = this.rect.findIndex(r => touch.pageX >= r.left && touch.pageX <= r.right && touch.pageY >= r.top && touch.pageY <= r.bottom )
				//如果当前坐标点有按钮，如果允许重复，需要判断上一个记录按钮是否和当前按钮相同，避免重复添加，如果不允许重复，需要判断当前按钮是否已经记录
				if ( index > -1 && (this.allowRepeat ? this.selected[this.selected.length-1].value != this.data[index] : this.selected.findIndex(s => s.value == this.data[index]) == -1) ) {
					//先将上个直线位置固定
					const s = this.selected[this.selected.length-1]
					const deltaY = this.rect[index].centerTop - s.top
					const deltaX = this.rect[index].centerLeft - s.left
					//根据坐标位置计算旋转角度
					s.rotate = Math.atan2(deltaY, deltaX) * (180 / Math.PI)
					//计算直线宽度
					s.width = Math.sqrt(deltaX * deltaX + deltaY * deltaY)
					//结束该条直线的绘制
					s.isFinish = true
					//开始画新的线
					this.selected.push({
						value: this.data[index],
						top: this.rect[index].centerTop,
						left: this.rect[index].centerLeft,
						rotate: 0,
						width: 0,
						isFinish: false
					})
				}
			},
			touchend () {
				this.selected = this.selected.map(s => {
					return s.isFinish ? s : {...s, width: 0, rotate: 0}
				})
				if ( this.selected.length > 0 ) this.$emit('finish', this.selected.map(s => s.value).join(''))
			},
			//重置状态
			reset () {
				this.isTouch = false
				this.selected = []
			},
			getRect (el) {
				return new Promise(resolve => {
					dom.getComponentRect(el, res => {
						resolve(res.size)
					})
				})
			}
		}
	}
</script>

<style>
	.com-gesture-password .pwd-btn {
		width: 100rpx;
		height: 100rpx;
		border-radius: 100rpx;
	}
	.com-gesture-password .pwd-btn-circle {
		width: 40rpx;
		height: 40rpx;
		border-radius: 40rpx;
	}
	.com-gesture-password .line {
		height: 5px;
		transform-origin: 0 2.5px;
	}
</style>